/**
 * Copyright (c) 2013-2014 Tomas Dzetkulic
 * Copyright (c) 2013-2014 Pavol Rusnak
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

//#include <check.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "aes.h"
#include "bignum.h"
//#include "base58.h"
//#include "bip32.h"
//#include "bip39.h"
//#include "ecdsa.h"
//#include "pbkdf2.h"
//#include "rand.h"
//#include "sha2.h"
//#include "options.h"
//#include "secp256k1.h"
//#include "nist256p1.h"

uint8_t *fromhex(const char *str)
{
	static uint8_t buf[128];
	uint8_t c;
	size_t i;
	for (i = 0; i < strlen(str) / 2; i++) {
		c = 0;
		if (str[i*2] >= '0' && str[i*2] <= '9') c += (str[i*2] - '0') << 4;
		if (str[i*2] >= 'a' && str[i*2] <= 'f') c += (10 + str[i*2] - 'a') << 4;
		if (str[i*2] >= 'A' && str[i*2] <= 'F') c += (10 + str[i*2] - 'A') << 4;
		if (str[i*2+1] >= '0' && str[i*2+1] <= '9') c += (str[i*2+1] - '0');
		if (str[i*2+1] >= 'a' && str[i*2+1] <= 'f') c += (10 + str[i*2+1] - 'a');
		if (str[i*2+1] >= 'A' && str[i*2+1] <= 'F') c += (10 + str[i*2+1] - 'A');
		buf[i] = c;
	}
	return buf;
}

char *tohex(const uint8_t *bin, size_t l)
{
	char *buf = (char *)malloc(l * 2 + 1);
	static char digits[] = "0123456789abcdef";
	size_t i;
	for (i = 0; i < l; i++) {
		buf[i*2  ] = digits[(bin[i] >> 4) & 0xF];
		buf[i*2+1] = digits[bin[i] & 0xF];
	}
	buf[l * 2] = 0;
	return buf;
}



#define test_deterministic(KEY, MSG, K) do { \
	sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
	res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \
	ck_assert_int_eq(res, 0); \
	bn_write_be(&k, buf); \
	ck_assert_mem_eq(buf, fromhex(K), 32); \
} while (0)



// test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors
test_aes(test_aes)
{
	aes_encrypt_ctx ctxe;
	aes_decrypt_ctx ctxd;
	uint8_t ibuf[16], obuf[16], iv[16], cbuf[16], i;
	const char **ivp, **plainp, **cipherp;

	// ECB
	static const char *ecb_vector[] = {
		// plain                            cipher
		"6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8",
		"ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870",
		"30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d",
		"f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7",
		
		//AES
		"6bc1bee22e409f96e93d7e117393172a", "e77afd626136bce21a86f47c132d193e",
		"ae2d8a571e03ac9c9eb76fac45af8e51", "07ad10f0db1a1ecad5dd3ce1c63de7e1",
		"30c81c46a35ce411e5fbc1191a0a52ef", "edb4a18a74db202375fec3065bcb15f8",
		"f69f2445df4f9b17ad2b417be66c3710", "66d5bfceb0ab26a6c343312cd95fc2ae",
		0, 0,
	};
	// CBC
	static const char *cbc_vector[] = {
		// iv                               plain                               cipher
		"000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "f58c4c04d6e5f1ba779eabfb5f7bfbd6",
		"F58C4C04D6E5F1BA779EABFB5F7BFBD6", "ae2d8a571e03ac9c9eb76fac45af8e51", "9cfc4e967edb808d679f777bc6702c7d",
		"9CFC4E967EDB808D679F777BC6702C7D", "30c81c46a35ce411e5fbc1191a0a52ef", "39f23369a9d9bacfa530e26304231461",
		"39F23369A9D9BACFA530E26304231461", "f69f2445df4f9b17ad2b417be66c3710", "b2eb05e2c39be9fcda6c19078c6a9d1b",
		0, 0, 0,
	};
	// CFB
	static const char *cfb_vector[] = {
		"000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "DC7E84BFDA79164B7ECD8486985D3860",
		"DC7E84BFDA79164B7ECD8486985D3860", "ae2d8a571e03ac9c9eb76fac45af8e51", "39ffed143b28b1c832113c6331e5407b",
		"39FFED143B28B1C832113C6331E5407B", "30c81c46a35ce411e5fbc1191a0a52ef", "df10132415e54b92a13ed0a8267ae2f9",
		"DF10132415E54B92A13ED0A8267AE2F9", "f69f2445df4f9b17ad2b417be66c3710", "75a385741ab9cef82031623d55b1e471",
		0, 0, 0,
	};
	// OFB
	static const char *ofb_vector[] = {
		"000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "dc7e84bfda79164b7ecd8486985d3860",
		"B7BF3A5DF43989DD97F0FA97EBCE2F4A", "ae2d8a571e03ac9c9eb76fac45af8e51", "4febdc6740d20b3ac88f6ad82a4fb08d",
		"E1C656305ED1A7A6563805746FE03EDC", "30c81c46a35ce411e5fbc1191a0a52ef", "71ab47a086e86eedf39d1c5bba97c408",
		"41635BE625B48AFC1666DD42A09D96E7", "f69f2445df4f9b17ad2b417be66c3710", "0126141d67f37be8538f5a8be740e484",
		0, 0, 0,
	};
	// CTR
	static const char *ctr_vector[] = {
		// plain                            cipher
		"6bc1bee22e409f96e93d7e117393172a", "601ec313775789a5b7a7f504bbf3d228",
		"ae2d8a571e03ac9c9eb76fac45af8e51", "f443e3ca4d62b59aca84e990cacaf5c5",
		"30c81c46a35ce411e5fbc1191a0a52ef", "2b0930daa23de94ce87017ba2d84988d",
		"f69f2445df4f9b17ad2b417be66c3710", "dfc9c58db67aada613c2dd08457941a6",
		0, 0,
	};
	
	plainp = ecb_vector;
	cipherp = ecb_vector + 1;
	while (*plainp && *cipherp) {
/*		// encrypt
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_ecb_encrypt(ibuf, obuf, 16, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		
		printf ("\n---------------cipherp--------------------\n");
		printf ("%s\n", tohex(obuf, 16));
		
		// decrypt
		aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd);
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_ecb_decrypt(ibuf, obuf, 16, &ctxd);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		printf ("\n---------------plainp--------------------\n");
		printf ("%s\n", tohex(obuf, 16));
		plainp += 2; cipherp += 2;

*/

		//test dh key
		aes_encrypt_key128(fromhex("00000000000000005a9fe6fb03c07905"), &ctxe);
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_ecb_encrypt(ibuf, obuf, 16, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		
		printf ("\n---------------128 cipherp--------------------\n");
		printf ("%s\n", tohex(obuf, 16));
		
		// decrypt
		aes_decrypt_key128(fromhex("00000000000000005a9fe6fb03c07905"), &ctxd);
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_ecb_decrypt(ibuf, obuf, 16, &ctxd);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		printf ("\n---------------128 plainp--------------------\n");
		printf ("%s\n", tohex(obuf, 16));
		plainp += 2; cipherp += 2;
	}

	
	ivp = cbc_vector;
	plainp = cbc_vector + 1;
	cipherp = cbc_vector + 2;
	while (*plainp && *cipherp) {
		// encrypt
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		// decrypt
		aes_decrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxd);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		ivp += 3; plainp += 3; cipherp += 3;
	}

	
	ivp = cfb_vector;
	plainp = cfb_vector + 1;
	cipherp = cfb_vector + 2;
	while (*plainp && *cipherp) {
		// encrypt
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		// decrypt (uses encryption)
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		ivp += 3; plainp += 3; cipherp += 3;
	}

	
	ivp = ofb_vector;
	plainp = ofb_vector + 1;
	cipherp = ofb_vector + 2;
	while (*plainp && *cipherp) {
		// encrypt
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		// decrypt (uses encryption)
		aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
		memcpy(iv, fromhex(*ivp), 16);
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		ivp += 3; plainp += 3; cipherp += 3;
	}

	
	// encrypt
	plainp = ctr_vector;
	cipherp = ctr_vector + 1;
	memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16);
	aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
	while (*plainp && *cipherp) {
		memcpy(ibuf, fromhex(*plainp), 16);
		aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*cipherp), 16);
		plainp += 2; cipherp += 2;
	}
	// decrypt (uses encryption)
	plainp = ctr_vector;
	cipherp = ctr_vector + 1;
	memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16);
	aes_encrypt_key256(fromhex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), &ctxe);
	while (*plainp && *cipherp) {
		memcpy(ibuf, fromhex(*cipherp), 16);
		aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe);
		//ck_assert_mem_eq(obuf, fromhex(*plainp), 16);
		plainp += 2; cipherp += 2;
	}
}


